home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / telecomm / archivers / md100b4.lha / MassDecode / MassDecode.rexx < prev    next >
OS/2 REXX Batch file  |  1994-03-11  |  57KB  |  1,561 lines

  1. /***************************************************************************
  2.  
  3.  
  4.                                MassDecode
  5.  
  6.  
  7.                       Copyright ©1994 by Gregg Giles
  8.  
  9.      BETA CODE - DO NOT REDISTRIBUTE - BETA CODE - DO NOT REDISTRIBUTE
  10.  
  11.  
  12. ***************************************************************************/
  13.  
  14.  
  15. /***************************************************************************
  16. GET COMMAND LINE ARGUMENTS
  17. ***************************************************************************/
  18.  
  19. parse arg arguments
  20.  
  21.  
  22.  
  23. /***************************************************************************
  24. DEFINITIONS
  25. Warning: be sure to check the scope!
  26. ***************************************************************************/
  27.  
  28. /* Default decoder */
  29. UUDECODER   = 'SmartDecode'         /* default decoder path */
  30.  
  31. /* Newsgroup name */
  32. NEWSGROUP   = 'alt.binaries.pictures.erotica'    /*** NOT IMPLEMENTED ***/
  33.  
  34. /* MassDecode log file directory */
  35. LOGS        = 'md:MassDecode/logs/'                    /*** NOT IMPLEMENTED ***/
  36.  
  37. /* Progam definitions */
  38. PROG_AUTHOR    = 'Gregg Giles'      /* author */
  39. PROG_COPYRIGHT = '1994'             /* Copyright */
  40. PROG_DATE      = '11 March 1994'    /* release date */
  41. PROG_NAME      = 'MassDecode'       /* program name */
  42. PROG_VERSION   = '1.00 Beta-4'      /* program version */
  43.  
  44. /* global definitions */
  45. OFF       = 0                       /* test condition */
  46. ON        = 1                       /* test condition */
  47. NO        = 0                       /* test condition */
  48. YES       = 1                       /* test condition */
  49. TEMP_DATE = ' '                     /* date */
  50. TEMP_TIME = ' '                     /* time */
  51. QUIET     = OFF                     /* controls console output */
  52.  
  53. /* counters */
  54. ctr_HeaderLine = 0                  /* counter: tracks current line # of message header */
  55.  
  56. /* file's message header structure */
  57. HEADER.            = 0               /* structure for file's message header */
  58. HEADER.LINES       = 0               /* number of lines in header */
  59. HEADER.SEARCH_MAX = 50                   /* number of lines after which to stop looking for header data */
  60.  
  61. /* message file information structure */
  62. UUFILE.           = 0
  63. UUFILE.INNAME     = '<inname>'      /* name of input file (no path) */
  64. UUFILE.INPATH     = '<inpath>'      /* path to input file (no name) */
  65. UUFILE.INPATHNAME = '<inpathname>'  /* path and filename of input file */
  66. UUFILE.OUTNAME    = '<outname>'     /* name of output file (no path) */
  67. UUFILE.OUTPATH    = '<outpath>'     /* path to output file (no name) */
  68. UUFILE.OUTPATHNAME= '<outpathname>' /* path and filename of output file */
  69. UUFILE.PARTNUM    = 0               /* part number of file's message */
  70. UUFILE.PARTSTOTAL = 0               /* total parts to file's message */
  71. UUFILE.SUBJECT    = '<subject>'     /* subject of file's message */
  72. UUFILE.UUENCODER  = '<uuencoder>'   /* uuencoder used to create file's message */
  73. UUFILE.VALID      = NO              /* tells if file contains valid uuencoded msg */
  74.  
  75. /* Totals */
  76. TOTALS.        = 0                  /* totals information structure */
  77. TOTALS.VALID   = 0                  /* number of valid uudecoded messages found */
  78. TOTALS.MSGS    = 0                  /* number of messages examined */
  79. TOTALS.DECODED = 0                  /* number binaries created */
  80.  
  81.  
  82.  
  83. /***************************************************************************
  84. CONSOLE OUTPUT
  85. If told to do so, turn off console I/O completely
  86. ***************************************************************************/
  87.  
  88. if (find(upper(arguments), 'QUIET')>0) then do
  89.    QUIET = ON
  90. end
  91.  
  92.  
  93.  
  94. /***************************************************************************
  95. DISPLAY PROGRAM INFORMATION
  96. ***************************************************************************/
  97.  
  98. if (QUIET = OFF) then do
  99.    say PROG_NAME 'Version' PROG_VERSION '('PROG_DATE')'
  100.    say 'Copyright ©'PROG_COPYRIGHT 'by' PROG_AUTHOR
  101.    say ''
  102. end
  103.  
  104.  
  105. /***************************************************************************
  106. DISPLAY USAGE TEMPLATE IF NO ARGUMENTS ARE GIVEN
  107. ***************************************************************************/
  108.  
  109. if (words(arguments)=0) then do
  110.     say 'Usage: rx MassDecode SOURCE <source_dir> DEST <dest_dir>'
  111.     say '                     [DECODER <path/name>] [HEADERLINES <max_lines>]'
  112.     say '                     [DEBUG=<level>] [QUIET]'
  113. end
  114.  
  115.  
  116.  
  117. /***************************************************************************
  118. DEBUGGING LEVEL
  119. Higher levels increase verbosity
  120. ***************************************************************************/
  121.  
  122. DEBUG = 0                           /* default debugging value */
  123. LOC_DEBUG = pos('DEBUG=', upper(arguments))
  124.  
  125. if (LOC_DEBUG > 0) then do
  126.    DEBUG = substr(arguments, LOC_DEBUG+length('DEBUG='), 1)
  127.    if ((DEBUG<0)|(DEBUG>9)) then do
  128.       say 'Error: Invalid DEBUG value - not displaying debug information'
  129.    end
  130. end
  131.  
  132.  
  133.  
  134. /***************************************************************************
  135. GET SOURCE DIRECTORY FROM PARAMETERS
  136. ***************************************************************************/
  137.  
  138. POS_SOURCE = find(upper(arguments), 'SOURCE')
  139.  
  140. /* If no source directory was supplied, show error message, then exit */
  141. if (POS_SOURCE=0) then do
  142.    say 'Error: no source directory specified'
  143.    exit                          /* exit program */
  144. end
  145.  
  146. SOURCE_DIR = word(arguments, POS_SOURCE+1)   /* get source from arguments */
  147.  
  148. /* Ensure source dir has colon or slash on end, otherwise program will fail */
  149. TMP_CHAR = right(SOURCE_DIR, 1)
  150. if ((TMP_CHAR ~= '/')&(TMP_CHAR ~= ':')) then do
  151.    if (DEBUG >= 5) then do
  152.       say '*** Forcing slash onto end of source directory path'
  153.    end
  154.    SOURCE_DIR = SOURCE_DIR'/'             /* force slash onto end */
  155. end
  156.  
  157.  
  158.  
  159. /***************************************************************************
  160. GET DESTINATION DIRECTORY FROM PARAMETERS
  161. ***************************************************************************/
  162.  
  163. POS_DEST = find(upper(arguments), 'DEST')
  164.  
  165. /* If no destination directory was supplied, show error message, then exit */
  166. if (POS_DEST=0) then do
  167.    say 'Error: no destination directory specified'
  168.    exit                          /* exit program */
  169. end
  170.  
  171. DEST_DIR = word(arguments, POS_DEST+1)    /* get destination from arguments */
  172.  
  173. /* Ensure dest dir has colon or slash on end, otherwise program will fail */
  174. TMP_CHAR = right(DEST_DIR, 1)
  175. if ((TMP_CHAR ~= '/')&(TMP_CHAR ~= ':')) then do
  176.    if (DEBUG >= 5) then do
  177.       say '*** Forcing slash onto end of destination directory path'
  178.    end
  179.    DEST_DIR = DEST_DIR'/'             /* force slash onto end */
  180. end
  181.  
  182.  
  183.  
  184. /***************************************************************************
  185. GET HEADERLINES VALUE FROM PARAMATERS
  186. The "HEADERLINES" variable specifies how many lines of the input file can
  187. be looked through before the search for header data is aborted. Normally,
  188. this value isn't needed when uuencoded data is found; however, it is 
  189. provided as a safety feature to prevent slowdowns caused by searching an
  190. entire input file which has no uuencoded data.
  191. **************************************************************************/
  192.  
  193. POS_HEADERLINES = find(upper(arguments), 'HEADERLINES')
  194.  
  195. if (POS_HEADERLINES > 0) then do
  196.     HEADER.SEARCH_MAX = word(arguments, POS_HEADERLINES+1)
  197.     if (DEBUG >= 5) then do
  198.         say '*** HEADER.SEARCH_MAX='HEADER.SEARCH_MAX
  199.     end
  200. end
  201.  
  202.  
  203.  
  204. /***************************************************************************
  205. GET DECODER FROM PARAMETERS
  206. If an alternate decoder is specified, check to make sure it exists, and if
  207. it does, use it.
  208. ***************************************************************************/
  209.  
  210. POS_UUDECODER = find(upper(arguments), 'DECODER')
  211.  
  212. if (POS_UUDECODER > 0) then do
  213.     WORD_UUDECODER = word(arguments, POS_UUDECODER+1)
  214.     if (exists(WORD_UUDECODER)>0) then do
  215.         UUDECODER = WORD_UUDECODER
  216.         if (DEBUG >= 5) then do
  217.             say '*** UUDECODER='UUDECODER
  218.         end
  219.     end
  220. end
  221.  
  222.  
  223.  
  224. /***************************************************************************
  225.  Open rexxsupport.library if not already open
  226. ***************************************************************************/
  227.  
  228. /* Open rexxsupport.library if not open */
  229. if ~show('L', 'rexxsupport.library') then do
  230.    if addlib('rexxsupport.library', 0, -30, 0) then do
  231.       if (DEBUG >= 6) then do
  232.          say 'Added rexxsupport.library'
  233.       end
  234.    end
  235.    else do
  236.       say 'Error: cannot open rexxsupport.library'
  237.       exit 10
  238.    end
  239. end
  240.  
  241.  
  242. /***************************************************************************
  243. GET SOURCE_DIR INFORMATION
  244. ***************************************************************************/
  245.  
  246. if (QUIET = OFF) then do
  247.    say 'Phase: Scanning source directory'
  248.    say ''
  249. end
  250.  
  251. /* If source directory doesn't exist, issue error message and exit */
  252. if (exists(SOURCE_DIR)=0) then do
  253.    say 'Error: source directory doesn''t exist ("'SOURCE_DIR'")'
  254.    exit                                      /* exit program*/
  255. end
  256.  
  257. /* get filenames from directory and stuff them into a string */
  258. if (DEBUG >= 1) then do
  259.    say 'Processing:' SOURCE_DIR
  260. end
  261. DIR_CONTENTS = showdir(SOURCE_DIR, 'f')
  262.  
  263. /* get the total number of files in specified directory */
  264. NUM_FILES = words(DIR_CONTENTS)
  265. TOTALS.MSGS = NUM_FILES
  266. if (DEBUG >= 5) then do
  267.    say '*** NUM_FILES='NUM_FILES
  268. end
  269.  
  270.  
  271. /***************************************************************************
  272. GENERATE TEMPORARY DATAFILE NAME
  273. This data file is used to store information for the decode phase
  274. ***************************************************************************/
  275.  
  276. TEMP_DATE = space(date(julian), 0)
  277. TEMP_TIME = space(time(seconds), 0)
  278. TEMPDATAFILENAME = 'MD_'TEMP_DATE''TEMP_TIME'.TMP'
  279. if (DEBUG >= 1) then do
  280.    say 'Datafile:' TEMPDATAFILENAME
  281. end
  282.  
  283. /* Create the data file */
  284. result = open('TEMPDATA', TEMPDATAFILENAME, write)
  285. result = close('TEMPDATA')
  286.  
  287. /***************************************************************************
  288. INTERPRET FILES
  289. ***************************************************************************/
  290.  
  291. /* display message that file interpretation has begun */
  292. if (QUIET = OFF) then do
  293.    say 'Phase: Recognition'
  294.    say ''
  295. end
  296.  
  297. /* Process each file until all have been interpreted */
  298. do ctr=1 to NUM_FILES
  299.    if (QUIET = OFF) then do
  300.       say 'Checking file' ctr 'of' NUM_FILES
  301.    end
  302.  
  303.    /* Reset defaults */
  304.    UUFILE.INNAME     = word(DIR_CONTENTS, ctr)  /* get name of input file (without path) */
  305.    UUFILE.INPATH     = SOURCE_DIR               /* get path to input file */
  306.    UUFILE.INPATHNAME = UUFILE.INPATH''UUFILE.INNAME   /* make input file pathname */
  307.    UUFILE.OUTNAME    = '<reset>'                /* output file name */
  308.    UUFILE.OUTPATH    = '<reset>'                /* output path */
  309.    UUFILE.OUTPATHNAME= '<reset>'                /* output pathname */
  310.    UUFILE.PARTNUM    = 0                        /* file's message part number */
  311.    UUFILE.PARTSTOTAL = 0                        /* total parts to message */
  312.    UUFILE.SUBJECT    = '<reset>'                /* input file's subject */
  313.    UUFILE.UUENCODER  = '<reset>'                /* file's message uuencoder */
  314.    UUFILE.VALID      = NO                       /* valid uuencoded msg in file? */
  315.  
  316.  
  317.    /************************************************************************
  318.    OPEN FILE FOR READING
  319.    ************************************************************************/
  320.  
  321.    if (DEBUG >= 5) then do
  322.       say '*** UUFILE.INPATHNAME='UUFILE.INPATHNAME
  323.    end
  324.    result = open('datafile', UUFILE.INPATHNAME, read)
  325.  
  326.  
  327.    /************************************************************************
  328.    READ IN MESSAGE HEADER FROM FILE
  329.    By reading in the header of the message, it should be possible to
  330.    determine everything needed to uudecode the file properly, including the
  331.    name, and part number if the uuencoded binary is spread across multiple
  332.    messages.
  333.    ************************************************************************/
  334.  
  335.    /* Initialize the array used to store the file's mesage header */
  336.    /***HEADER.        = 0***/
  337.  
  338.    /* Reset flag which determines if reading from file should be stopped */
  339.    STOP           = NO     /* reset loop control flag */
  340.    ctr_HeaderLine = 1      /* reset header line counter */
  341.    MCOUNTER       = 0      /* safety counter: counts uuencode data line */
  342.    PERCENT        = 0      /* percentage of messages examined that are uuencoded */
  343.  
  344.    /* Read from file until the actual uuencoded data is reached (or EOF) */
  345.    do until (STOP=YES)
  346.       instring = readln('datafile')          /* read line from file */
  347.  
  348.       HEADER.ctr_HeaderLine = instring       /* copy line into header structure */
  349.       if (DEBUG >= 9) then do
  350.          say ctr_HeaderLine' 'HEADER.ctr_HeaderLine
  351.       end
  352.  
  353.       /* Count lines which begin with "M" - data lines in uuencoded messages
  354.          begin with "M"; this is a safety in case messages such as parts do
  355.          not have "begin" lines */
  356.       if (left(HEADER.ctr_HeaderLine, 1) = 'M') then do
  357.          MCOUNTER = MCOUNTER + 1
  358.       end
  359.  
  360.       ctr_HeaderLine = ctr_HeaderLine + 1    /* bump header line counter */
  361.  
  362.       /* stop if uuencoded data or end of file is reached (case-sensitive) */
  363.       FIRSTWORD = left(instring, 5)
  364.       if ((FIRSTWORD = 'BEGIN')|(FIRSTWORD = 'begin')|(MCOUNTER=5)|(eof('datafile'))) then do
  365.          /* Read in one additional line - this is done to catch a possible
  366.             subsequent line which contains the actual "begin 644 filename"
  367.             field of a uuencoded message. */
  368.          instring = readln('datafile')       /* read extra line from file */
  369.          HEADER.ctr_HeaderLine = instring    /* copy line into header structure */
  370.          HEADER.LINES = ctr_HeaderLine +1    /* make note of # lines in header (plus one additional line) */
  371.          STOP = YES
  372.       end
  373.  
  374.         if (DEBUG >= 5) then do
  375.             say '*** ctr_HeaderLine='ctr_HeaderLine 'HEADER.SEARCH_MAX='HEADER.SEARCH_MAX
  376.         end
  377.  
  378.         /* Stop if number of lines searched exceeds specified maximum */
  379.         if (ctr_HeaderLine = HEADER.SEARCH_MAX) then do
  380.             if (DEBUG >= 5) then do
  381.                 say '*** Stopping header information search - headerlines limit reached'
  382.             end
  383.             HEADER.LINES = ctr_HeaderLine + 1    /* make note of # lines in header (plus one additional line) */
  384.             STOP = YES
  385.         end
  386.    end
  387.  
  388.  
  389.    /************************************************************************
  390.    CLOSE FILE
  391.    ************************************************************************/
  392.  
  393.    result = close('datafile')
  394.  
  395.  
  396.    /************************************************************************
  397.    SHOW BACK THE CONTENTS OF THE HEADER STRUCTURE
  398.    Used for testing purposes only
  399.    ************************************************************************/
  400.  
  401.    if (DEBUG >= 9) then do
  402.       ctr_HeaderLine = 1
  403.       say '*** HEADER.LINES='HEADER.LINES
  404.       do until (ctr_HeaderLine = HEADER.LINES)
  405.          say ctr_HeaderLine' 'HEADER.ctr_HeaderLine
  406.          ctr_HeaderLine = ctr_HeaderLine + 1
  407.       end
  408.    end
  409.  
  410.  
  411.  
  412.    /************************************************************************
  413.    PROCESS HEADER
  414.    Check to see if file's contents contain a valid UUCP message, and if so,
  415.    what type, etc.
  416.    ************************************************************************/
  417.  
  418.    if (DEBUG >= 5) then do
  419.       say '*** process_header()'
  420.    end
  421.  
  422.    result = PROCESS_HEADER()
  423.    if (UUFILE.VALID = YES) then TOTALS.VALID = TOTALS.VALID + 1
  424.  
  425.  
  426.  
  427.    /************************************************************************
  428.    CLEAR HEADER STRUCTURE
  429.    Once the file has been dealt with, empty the header structure so data
  430.    isn't accidentally applied to the next file
  431.    ************************************************************************/
  432.  
  433.    if (DEBUG >= 6) then do
  434.       say 'clearing header structure'
  435.    end
  436.    ctr_HeaderLine = 1
  437.    do until (ctr_HeaderLine = HEADER.LINES)
  438.       HEADER.ctr_HeaderLine = ' '
  439.       ctr_HeaderLine = ctr_HeaderLine + 1
  440.    end
  441.  
  442.  
  443.  
  444.    /***********************************************************************
  445.    REMOVE INVALID CHARACTERS FROM ENTRY'S BINARY NAME
  446.    ************************************************************************/
  447.  
  448.    /* Remove carriage return (ASCII decimal 13, hex '0x0D') */
  449.    CR = x2c('0D')
  450.    UUFILE.OUTNAME = compress(UUFILE.OUTNAME, CR)
  451.  
  452.  
  453.  
  454.    /************************************************************************
  455.    DISPLAY INFORMATION ABOUT FILE AND MESSAGE
  456.    ************************************************************************/
  457.  
  458.    if (QUIET = OFF) then do
  459.       if (DEBUG >= 5) then do
  460.          say '*** Header lines:' HEADER.LINES
  461.       end
  462.       say 'Source :' UUFILE.INNAME
  463.       say 'Subject:' UUFILE.SUBJECT                  /* display message subject */
  464.  
  465.       if (UUFILE.VALID = YES) then do
  466.          say 'Encoder:' UUFILE.UUENCODER
  467.          say 'Part No:' UUFILE.PARTNUM 'of' UUFILE.PARTSTOTAL
  468.          say 'Binary :' UUFILE.OUTNAME
  469.       end
  470.       else do
  471.          say 'Note   : File doesn''t contain valid/recognizable uuencoded data.'
  472.       end
  473.       say ''
  474.    end
  475.  
  476.  
  477.  
  478.    /************************************************************************
  479.    PUT FILE INFORMATION INTO TEMPORARY DATA FILE
  480.    Do not add an entry to the data file if it is not a valid message
  481.    ************************************************************************/
  482.  
  483.    if (UUFILE.VALID = YES) then do
  484.       OUT_STRING = UUFILE.INNAME UUFILE.OUTNAME UUFILE.PARTNUM UUFILE.PARTSTOTAL
  485.       result = open('TEMPDATA', TEMPDATAFILENAME, Append)
  486.       writeln('TEMPDATA', OUT_STRING)
  487.       result = close('TEMPDATA')
  488.    end
  489.  
  490. end
  491.  
  492.  
  493.  
  494. /***************************************************************************
  495. DISPLAY TOTALS
  496. ***************************************************************************/
  497.  
  498. if (QUIET = OFF) then do
  499.    PERCENT = ((TOTALS.VALID/TOTALS.MSGS)*100)
  500.    PERCENT = trunc(PERCENT, 2)
  501.    say 'Total files examined :' TOTALS.MSGS
  502.    say 'Valid uuencoded parts:' TOTALS.VALID '('PERCENT'%)'
  503. end
  504.  
  505.  
  506.  
  507. /***************************************************************************
  508. SORT THE DATA ARRAY
  509. ***************************************************************************/
  510.  
  511. ctr_init          = 0   /* counter: initilization loop */
  512. ctr_infileline    = 0   /* counter: current line of input file */
  513. LIST.             = ' ' /* initialize data array */
  514. LIST.TOTALENTRIES = 0   /* total entries in array */
  515.  
  516. if (QUIET = OFF) then do
  517.    say ''
  518.    say 'Phase: Sorting entries'
  519.    say ''
  520. end
  521.  
  522. /* Open temp data file for reading */
  523. result = open('TEMPDATA', TEMPDATAFILENAME, read)
  524.  
  525. if (DEBUG >= 5) then do
  526.    say '*** TOTALS.VALID='TOTALS.VALID '(# expected lines in file)'
  527. end
  528.  
  529. /* Read through each line of temporary data file. Note: the number of lines
  530.    in the file should be identical to the number of valid uuencoded messages
  531.    which were found. */
  532.  
  533. do ctr_infileline=1 to TOTALS.VALID
  534.    /* read line from file */
  535.    instring = readln('TEMPDATA')
  536.  
  537.    /* Disect line */
  538.    PARTNAME    = word(instring, 1)  /* actual file containing binary part */
  539.    BINARYNAME  = word(instring, 2)  /* name of eventual resulting binary */
  540.    PARTNUM     = word(instring, 3)  /* number of current part */
  541.    PARTSTOTAL  = word(instring, 4)  /* total number of parts to binary */
  542.  
  543.    if (DEBUG >= 5) then do
  544.         say ''
  545.       say '*** PARTNUM='PARTNUM  'PARTSTOTAL='PARTSTOTAL
  546.    end
  547.  
  548.  
  549.    /************************************************************************
  550.    SAFETY CHECK FOR PART/TOTAL VALUES
  551.    Force part number to 1 and part total to 1 if total parts is zero. This
  552.    is done in case a file contains a binary which has no valid part numbers.
  553.    Note: this will not effect messages which are part 0 of (x) parts; this
  554.    only takes effect if the total number of parts is 0.
  555.    ************************************************************************/
  556.  
  557.    if (PARTSTOTAL = 0) then do
  558.       if (DEBUG >= 5) then do
  559.          say '*** Forcing PARTNUM to 1, PARTSTOTAL to 1'
  560.       end
  561.       PARTNUM = 1
  562.       PARTSTOTAL = 1
  563.    end
  564.  
  565.  
  566.    if (DEBUG >= 5) then do
  567.       say '*** PARTNUM='PARTNUM  'PARTSTOTAL='PARTSTOTAL
  568.    end
  569.  
  570.  
  571.    /* reset variables before entering loop (mandatory - do not move) */
  572.    STOP        = NO  /* loop */
  573.    ctr_entry   = 0   /* counts entries */
  574.  
  575.    /* Search through entry list to see if entry already exists for binary */
  576.    do until (STOP = YES)
  577.       if (DEBUG >= 5) then do
  578.          say '*** ctr_infileline='ctr_infileline 'ctr_entry='ctr_entry 'LIST.TOTALENTRIES='LIST.TOTALENTRIES 'LIST.'ctr_entry'='LIST.ctr_entry
  579.       end
  580.  
  581.       /* if an entry exists, add information to it */
  582.       if (LIST.ctr_entry = BINARYNAME) then do
  583.          if (DEBUG >= 5) then do
  584.             say BINARYNAME 'entry already exists'
  585.          end
  586.          STOP = YES           /* escape from the loop */
  587.  
  588.          /* Add part information to existing entry */
  589.          LIST.ctr_entry.PARTNUM = PARTNAME        /* copy part name into part entry */
  590.          if (DEBUG >= 5) then do
  591.             say '*** LIST.'ctr_entry'.'PARTNUM'=' LIST.ctr_entry.PARTNUM
  592.          end
  593.       end
  594.  
  595.       /* if no entry already exists, create one */
  596.       if (ctr_entry = LIST.TOTALENTRIES) then do
  597.          LIST.TOTALENTRIES = LIST.TOTALENTRIES + 1 /* bump entries counter */
  598.          LIST.ctr_entry = BINARYNAME               /* copy binary name into entry slot */
  599.          STOP = YES                                /* stop scanning through entry list */
  600.          if (DEBUG >= 5) then do
  601.             say 'Created entry' ctr_entry 'for' BINARYNAME '(Total entries:' LIST.TOTALENTRIES')'
  602.          end
  603.  
  604.          /* Initialize entry's part information (begin at one, go to last part) */
  605.          do ctr_part=1 to PARTSTOTAL
  606.             LIST.ctr_entry.ctr_part = '<undefined>'/* initilize the part entry */
  607.             LIST.ctr_entry.PARTNUM = PARTNAME      /* copy part name into part entry */
  608.             LIST.ctr_entry.MAXPARTS= PARTSTOTAL    /* make note of total number of parts for entry */
  609.             if (DEBUG >= 5) then do
  610.                say '*** LIST.'ctr_entry'.MAXPARTS=' LIST.ctr_entry.MAXPARTS
  611.                say '*** LIST.'ctr_entry'.'ctr_part'=' LIST.ctr_entry.ctr_part
  612.             end
  613.          end
  614.       end
  615.       ctr_entry = ctr_entry +1            /* bump entry counter */
  616.    end
  617.  
  618.  
  619.    /* display output */
  620.    if (QUIET = OFF) then do
  621.       say BINARYNAME '(part' PARTNUM 'of' PARTSTOTAL') - filename:' PARTNAME        
  622.    end
  623. end
  624.  
  625.  
  626. /* Close temp data file for reading */
  627. if (DEBUG >= 6) then do
  628.    say 'Closing:' TEMPDATAFILENAME
  629. end
  630. result = close('TEMPDATA')
  631. address command 'delete' TEMPDATAFILENAME 'quiet'
  632.  
  633.  
  634.  
  635. /***************************************************************************
  636. REDISPLAY ENTIRE CONTENTS OF THE NOW-SORTED LIST
  637. ***************************************************************************/
  638.  
  639. if (DEBUG >= 8) then do
  640.    say ''
  641.    say 'Current entries:'
  642.    do ctr_testentry=0 to (LIST.TOTALENTRIES-1)
  643.       say 'Binary:' LIST.ctr_testentry '(MAXPARTS='LIST.ctr_testentry.MAXPARTS')'
  644.       do ctr_testpart = 1 to LIST.ctr_testentry.MAXPARTS
  645.          say 'LIST.'ctr_testentry'.'ctr_testpart':' LIST.ctr_testentry.ctr_testpart
  646.       end
  647.       say ''
  648.    end
  649. end
  650.  
  651.  
  652.  
  653. /***************************************************************************
  654. CHECK FOR VALIDITY OF ENTRIES (DISQUALIFY INCOMPLETE ENTRIES)
  655. If an entry is missing any of its parts, then make note of it
  656. ***************************************************************************/
  657.  
  658. ctr_entry   = 0   /* counter: current entry */
  659. ctr_part    = 0   /* counter: current part of entry */
  660.  
  661. if (QUIET = OFF) then do
  662.    say ''
  663.    say 'Phase: Validating entries'
  664. end
  665.  
  666. /* Scan through all entries in list */
  667. do ctr_entry=0 to (LIST.TOTALENTRIES-1)
  668.    if (DEBUG >= 5) then do
  669.       say 'Binary:' LIST.ctr_entry
  670.    end
  671.    LIST.ctr_entry.VALIDENTRY = YES     /* by default, entries are valid until proven invalid */
  672.  
  673.    /* Scan through all parts of entry */
  674.    if (DEBUG >= 5) then do
  675.       say '*** MAXPARTS='LIST.ctr_entry.MAXPARTS
  676.    end
  677.    do ctr_part = 1 to LIST.ctr_entry.MAXPARTS
  678.       if (DEBUG >= 5) then do
  679.          say 'LIST.'ctr_entry'.'ctr_part':' LIST.ctr_entry.ctr_part
  680.       end
  681.  
  682.       /* If part has not been defined, skip on to the next entry. This is
  683.          done because if a single part is missing from the entry, then part
  684.          of the binary is missing. */
  685.       if (LIST.ctr_entry.ctr_part = '<undefined>') then do
  686.          LIST.ctr_entry.VALIDENTRY = NO      /* make entry invalid */
  687.          if (DEBUG >= 5) then do
  688.             say '*** Invalid entry'
  689.          end
  690.       end
  691.    end
  692.    if (LIST.ctr_entry.VALIDENTRY = NO) then do
  693.       if (DEBUG >= 5) then do
  694.          say 'Invalid entry - part missing'
  695.       end
  696.    end
  697. end
  698.  
  699.  
  700.  
  701. /***************************************************************************
  702. JOIN VALID ENTRIES
  703. Now the validity of each entry has been determined, join together the parts
  704. of each valid entry into an AmigaDOS file
  705. ***************************************************************************/
  706.  
  707. ctr_entry   = 0   /* counter: current entry */
  708. ctr_part    = 0   /* counter: current part of entry */
  709.  
  710. if (QUIET = OFF) then do
  711.    say ''
  712.    say 'Phase: Joining valid entries'
  713.    say ''
  714. end
  715.  
  716.  
  717.  
  718. /***************************************************************************
  719. ADD ENTRY TO LOG IF VALID, IF EXISTS IN LOG FLAG ENTRY AS INVALID
  720. If an entry is valid and is not already in the log, add it to the log so it
  721. won't be processed in the future. If an entry is valid and IS in the log
  722. already, mark it as invalid so it will not be processed (joined/decoded).
  723. ***************************************************************************/
  724.  
  725. /***
  726. If log exists, open it for reading (name is based upon newsgroup)
  727.    read file line by line until eof reached
  728.       get filename from line and assign to LOGDATA.<line_number>.LOG_FILENAME
  729.       get add date from line and assign to LOGDATA.<line_number>.LOG_DATEADDED
  730.       get add time from line and assign to LOGDATA.<line_number>.LOG_TIMEADDED
  731.    end
  732.    do ctr=1 to end of LIST structure (LIST will be compared to LOGDATA, not the other way around)
  733.       compare LIST's binary name to LOGDATA.<line_number>.LOG_FILENAME
  734.          if there's a match (entry was already processed), then LIST.ctr_entry.VALIDENTRY = NO
  735.          if there's NOT a match (entry was not already processed, then change
  736.             nothing (invalid entries will remain invalid)
  737.       end
  738.    end
  739. close log
  740.  
  741. If log does't exist, create it by opening it for writing (name is based upon newsgroup name)
  742.    scan through LIST struture entry by entry until end reached
  743.       if entry is valid
  744.          write binary name to line
  745.          write date added to line
  746.       end
  747.       if entry is invalid
  748.          do nothing
  749.       end
  750.    end of LIST structure reached
  751. close log
  752. ***/
  753.  
  754. /***
  755. /* Initialize the LOGDATA array */
  756. LOGDATA. = ' '
  757. ctr_line = 0
  758.  
  759. /* Generate name of log file (logfile name is based upon newsgroup name) */
  760. LOGNAME = LOGS''NEWSGROUP
  761. say '*** LOGNAME='LOGNAME
  762.  
  763. /* If log exists, open it for reading */
  764. if (exists(LOGNAME)>0) then do
  765.    say '***' LOGNAME 'exists, opening...'
  766.    result = open('LOGFILE', LOGNAME, read)               /* open log file */
  767.    say '*** Reading log file'
  768.    do until(eof(LOGNAME))
  769.       instring = readln('LOGFILE')                       /* read line */
  770.       LOGDATA.ctr_line.LOG_FILENAME = word(instring, 1)  /* get filename */
  771.       LOGDATA.ctr_line.LOG_DATEADDED = word(instring, 2) /* get date */
  772.       LOGDATA.ctr_line.LOG_TIMEADDED = word(instring, 3) /* get time */
  773.       ctr_line = ctr_line + 1                            /* bump counter*/
  774.       LOGDATA.ENTRIES = ctr_line                         /* tracks total entries in log structure */
  775.       say '***' ctr_line LOGDATA.ctr_line.LOG_FILENAME LOGDATA.ctr_line.LOG_DATEADDED LOGDATA.ctr_line.LOG_TIMEADDED
  776.    end
  777.  
  778.    /* compare LIST struct entries to LOGDATA entries */
  779.    do ctr_list=1 to LIST.TOTALENTRIES                    /* go through current entry data */
  780.       say '*** ctr_list='ctr_list
  781.       do ctr_log=1 to LOGDATA.ENTRIES                    /* go through log data */
  782.          /* Compare current list entry to name from log line */
  783.          if (LIST.ctr_list = LOGDATA.ctr_log.LOG_FILENAME) then do
  784.             LIST.ctr_list.VALIDENTRY = NO                /* in log, so don't process again */
  785.          end
  786.          say '*** ctr_log='ctr_log  'LISTname='LIST.ctr_list  'LOG_FILENAME='LOGDATA.ctr_log.LOG_FILENAME
  787.       end
  788.    end
  789.    say '*** Closing log'
  790.    result = close('LOGFILE')                             /* close log */
  791. end
  792. ***/
  793.  
  794.  
  795. /* If log doesn't exist, create it by opening it for writing */
  796.  
  797.  
  798.  
  799. /***************************************************************************
  800. GENERATE TEMPORARY DECODE SCRIPT NAME
  801. This data file is used to store information for the 'form binaries' phase
  802. ***************************************************************************/
  803.  
  804. TEMP_DATE = space(date(julian), 0)
  805. TEMP_TIME = space(time(seconds), 0)
  806. DECODESCRIPT = 'decode_'TEMP_DATE''TEMP_TIME'.scr'
  807. if (DEBUG >= 1) then do
  808.    say 'Decode script:' DECODESCRIPT
  809. end
  810.  
  811. /* Create the decode script */
  812. result = open('DECODEFILE', DECODESCRIPT, write)
  813. writeln('DECODEFILE', 'cd' DEST_DIR)
  814. result = close('DECODEFILE')
  815.  
  816.  
  817. /* Rescan the entry list and join only valid uuencoded parts (all parts of
  818.    a binary must be present for the joining to occur for that binary) */
  819.  
  820. do ctr_entry=0 to (LIST.TOTALENTRIES-1)
  821.    if (LIST.ctr_entry.VALIDENTRY = YES) then do
  822.       PART_STRING = ''              /* initialize string containing part names */
  823.       if (DEBUG >= 5) then do
  824.          say 'Binary:' LIST.ctr_entry
  825.       end
  826.  
  827.       /* Create string containing entry names to be joined */
  828.       do ctr_part = 1 to LIST.ctr_entry.MAXPARTS
  829.          if (DEBUG >= 5) then do
  830.             say 'LIST.'ctr_entry'.'ctr_part':' LIST.ctr_entry.ctr_part
  831.          end
  832.          PART_NAME   = SOURCE_DIR''LIST.ctr_entry.ctr_part
  833.          PART_STRING = PART_STRING' 'PART_NAME
  834.       end
  835.  
  836.  
  837.       /*********************************************************************
  838.       ADD ENTRY TO DECODE SCRIPT
  839.       The resulting script will be run late to decode all of the joined
  840.       binaries
  841.       *********************************************************************/
  842.  
  843.       messageline = 'echo "Decoding:' LIST.ctr_entry'"'
  844.       joinline    = 'join' PART_STRING 'TO' DEST_DIR''LIST.ctr_entry'.uu'
  845.       outline     = UUDECODER' 'DEST_DIR''LIST.ctr_entry'.uu'
  846.       deleteline  = 'delete' DEST_DIR''LIST.ctr_entry'.uu quiet'
  847.       if (DEBUG >= 5) then do
  848.          say outline
  849.       end
  850.       result = open('DECODEFILE', DECODESCRIPT, append)
  851.       if (QUIET = OFF) then do
  852.          writeln('DECODEFILE', messageline)  /* displays message to Shell */
  853.       end
  854.       writeln('DECODEFILE', joinline)        /* join parts */
  855.       writeln('DECODEFILE', outline)         /* decode joined file */
  856.       writeln('DECODEFILE', deleteline)      /* delete joined file, leaving binary behind */
  857.       result = close('DECODEFILE')           /* close file */
  858.       TOTALS.DECODED = TOTALS.DECODED + 1    /* bump counter */
  859.    end
  860. end
  861.  
  862.  
  863.  
  864. /***************************************************************************
  865. FORM BINARIES PHASE
  866. ***************************************************************************/
  867.  
  868. /* Execute the decode script */
  869. if (QUIET = OFF) then do
  870.    say 'Phase: Decoding'
  871.    say ''
  872. end
  873. address command 'execute' DECODESCRIPT
  874. address command 'delete' DECODESCRIPT 'quiet'
  875.  
  876.  
  877.  
  878. /***************************************************************************
  879. DISPLAY TOTALS
  880. ***************************************************************************/
  881.  
  882. if (QUIET = OFF) then do
  883.    PERCENT = ((TOTALS.VALID/TOTALS.MSGS)*100)
  884.    PERCENT = trunc(PERCENT, 2)
  885.    say ''
  886.    say 'Total files examined :' TOTALS.MSGS
  887.    say 'Valid uuencoded parts:' TOTALS.VALID '('PERCENT'%)'
  888.    say 'Total binaries formed:' TOTALS.DECODED
  889. end
  890.  
  891. exit /* program */
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901. PROCESS_HEADER: procedure expose HEADER. UUFILE. TOTALS. DEBUG
  902.  
  903. /***************************************************************************
  904. Local definitions
  905. ***************************************************************************/
  906.  
  907. SUCCESS = 1
  908. FAILURE = 0
  909.  
  910. YES = 1              /* test condition */
  911. NO  = 0              /* test condition */
  912. LOOKFORNAME = YES    /* continue looking for name of uuencoded binary */
  913.  
  914.  
  915.  
  916. /***************************************************************************
  917. SCAN THROUGH HEADER FOR SUBJECT LINE
  918. ***************************************************************************/
  919.  
  920. if (DEBUG >= 5) then do
  921.    say '*** Subject part search'
  922. end
  923.  
  924. do ctr_line = 1 to HEADER.LINES
  925.    if (upper(word(HEADER.ctr_line, 1)) = "SUBJECT:") then do
  926.  
  927.       /* Ensure message is not a reply */
  928.       if (upper(word(HEADER.ctr_line, 2)) ~= "RE:") then do
  929.          UUFILE.SUBJECT = subword(HEADER.ctr_line, 2)
  930.  
  931.          /******************************************************************
  932.             SEARCH FOR BINARY NAME
  933.          Search for default filename in Subject line - this is not a test
  934.          condition (other tests may look for filenames; in such cases,
  935.          the results of those tests are used
  936.          ******************************************************************/
  937.  
  938.          EXTENSION.NUM= 29
  939.          EXTENSION.1  = '.anim'  /* ANIM (animation) */
  940.          EXTENSION.2  = '.anm'   /* ANIM (animation) */
  941.          EXTENSION.3  = '.arc'   /* ARC  (archive) */
  942.          EXTENSION.4  = '.arj'   /* ARJ  (archive) */
  943.          EXTENSION.5  = '.avi'   /* AVI  (animation) */
  944.          EXTENSION.6  = '.com'   /* COM  (executable; MS-DOS) */
  945.          EXTENSION.7  = '.dl'    /* DL   (animation) */
  946.          EXTENSION.8  = '.dms'   /* DMS  (archive; DiskMasher disk archiver, Amiga */
  947.          EXTENSION.9  = '.exe'   /* EXE  (executable; MS-DOS) */
  948.          EXTENSION.10 = '.g'     /* GIF  (image) */
  949.          EXTENSION.11 = '.gif'   /* GIF  (image) */
  950.          EXTENSION.12 = '.gl'    /* GL   (animation; Grasp) */
  951.          EXTENSION.13 = '.ham'   /* HAM  (image; Hold And Modify image)*/
  952.          EXTENSION.14 = '.iff'   /* IFF  (image or sound; Interchange File Format) */
  953.          EXTENSION.15 = '.j'     /* JPEG (image) */
  954.          EXTENSION.16 = '.jpeg'  /* JPEG (image) */
  955.          EXTENSION.17 = '.jpg'   /* JPEG (image) */
  956.          EXTENSION.18 = '.lha'   /* LHA  (archive) */
  957.          EXTENSION.19 = '.lzh'   /* LZH  (archive) */
  958.          EXTENSION.20 = '.mpeg'  /* MPEG (animation) */
  959.          EXTENSION.21 = '.mpg'   /* MPEG (animation) */
  960.          EXTENSION.22 = '.run'   /* RUN  (archive; self-extracting LZH/LHA) */
  961.          EXTENSION.23 = '.sda'   /* SEA  (archive; Self-Dissolving Archive) */
  962.          EXTENSION.24 = '.sea'   /* SEA  (archive; Self-Extracting Archive) */
  963.          EXTENSION.25 = '.tar'   /* TAR  (archive; Unix Tar) */
  964.          EXTENSION.26 = '.z'     /* Z    (archive; Unix compress) */
  965.          EXTENSION.27 = '.zip'   /* ZIP  (archive) */
  966.          EXTENSION.28 = '.zoo'   /* ZOO  (archive) */
  967.          EXTENSION.29 = '.zom'   /* ZOM  (archive; Zoom disk archiver, Amiga) */
  968.  
  969.  
  970.          /* get number of words in the subject line */
  971.          NUM_SUBJWORDS = words(UUFILE.SUBJECT)
  972.  
  973.          /* check each word of the subject line until all are checked */
  974.          do ctr_word = 1 to NUM_SUBJWORDS
  975.             TEMP_WORD = word(UUFILE.SUBJECT, ctr_word)
  976.  
  977.             /* check to see if possible extensions match any part of word */
  978.             do ctr_extension = 1 to EXTENSION.NUM
  979.                /* if there's a match, we've found the filename */
  980.                if (pos(EXTENSION.ctr_extension, TEMP_WORD)>0) then do
  981.                   if (DEBUG >= 5) then do
  982.                      say '*** found filename in subject'
  983.                   end
  984.                   UUFILE.OUTNAME = TEMP_WORD    /* set name */
  985.                   /*LOOKFORNAME    = NO*/           /* stop looking for name */
  986.                   leave ctr_word                /* escape from the loop */
  987.                end
  988.             end
  989.          end
  990.  
  991.  
  992.  
  993.          /******************************************************************
  994.             GENERIC PART NUMBER SEARCH
  995.          Search for part numbers in Subject line for use with filename -
  996.          this is not a test condition
  997.          ******************************************************************/
  998.  
  999.          if (upper(word(HEADER.ctr_line, 1)) = "SUBJECT:") then do
  1000.             /* zero variables used to find part number and totals */
  1001.             LEFT     = 0
  1002.             CENTER   = 0
  1003.             RIGHT    = 0
  1004.             CONTINUE = YES
  1005.  
  1006.  
  1007.  
  1008.                 /***************************************************************
  1009.                 GENERIC PART NUMBER SEARCH
  1010.             Check for part pattern: "[1/2]"
  1011.                 ***************************************************************/
  1012.  
  1013.             if (CONTINUE=YES) then do
  1014.                if (DEBUG >= 5) then do
  1015.                   say '*** [] search'
  1016.                end
  1017.                if (verify('[/]', HEADER.ctr_line)=0) then do
  1018.                   LEFT  = pos('[', HEADER.ctr_line)
  1019.                   CENTER= pos('/', HEADER.ctr_line)
  1020.                   RIGHT = pos(']', HEADER.ctr_line)
  1021.                   /* Make sure the pattern components found are part number,
  1022.                      not just erratic characters found in the Subject line */
  1023.                   if (LEFT<CENTER)&(RIGHT>CENTER) then do
  1024.                      UUFILE.PARTNUM    = substr(HEADER.ctr_line, LEFT+1, (CENTER-LEFT-1))
  1025.                      UUFILE.PARTSTOTAL = substr(HEADER.ctr_line, CENTER+1, (RIGHT-CENTER-1))
  1026.                      CONTINUE=NO       /* don't keep searching */
  1027.                   end
  1028.                end
  1029.             end
  1030.  
  1031.  
  1032.  
  1033.                 /***************************************************************
  1034.                 GENERIC PART NUMBER SEARCH
  1035.             Check for part pattern: "(1/2)"
  1036.                 ***************************************************************/
  1037.  
  1038.             if (CONTINUE=YES) then do
  1039.                if (DEBUG >= 5) then do
  1040.                   say '*** () search'
  1041.                end
  1042.                if (verify('(/)', HEADER.ctr_line)=0) then do
  1043.                   if (find(HEADER.ctr_line, '(part ')=0) then do  /* make sure this is NOT a '(part 1/2)' pattern */
  1044.                      LEFT  = pos('(', HEADER.ctr_line)
  1045.                      CENTER= pos('/', HEADER.ctr_line)
  1046.                      RIGHT = pos(')', HEADER.ctr_line)
  1047.                      /* Make sure the pattern components found are part number,
  1048.                         not just erratic characters found in the Subject line */
  1049.                      if (LEFT<CENTER)&(RIGHT>CENTER) then do
  1050.                         UUFILE.PARTNUM    = substr(HEADER.ctr_line, LEFT+1, (CENTER-LEFT-1))
  1051.                         UUFILE.PARTSTOTAL = substr(HEADER.ctr_line, CENTER+1, (RIGHT-CENTER-1))
  1052.                         CONTINUE=NO       /* don't keep searching */
  1053.                      end
  1054.                   end
  1055.                end
  1056.             end
  1057.  
  1058.  
  1059.  
  1060.                 /***************************************************************
  1061.                 GENERIC PART NUMBER SEARCH
  1062.             Check for part pattern: "(part 1/2)"
  1063.                 ***************************************************************/
  1064.           
  1065.             if (CONTINUE=YES) then do
  1066.                if (DEBUG >= 5) then do
  1067.                   say '*** (part x/y) search'
  1068.                end
  1069.                if (verify('(/)', HEADER.ctr_line)=0) then do
  1070.                   if (find(upper(HEADER.ctr_line), '(PART ')>0) then do  /* check for the '(part' phrase */
  1071.                      LEFT  = (pos('(', HEADER.ctr_line)+5)  /* LEFT begins AFTER the 'part ' keyword */
  1072.                      CENTER= pos('/', HEADER.ctr_line)
  1073.                      RIGHT = pos(')', HEADER.ctr_line)
  1074.                      /* Make sure the pattern components found are part number,
  1075.                         not just erratic characters found in the Subject line */
  1076.                      if (LEFT<CENTER)&(RIGHT>CENTER) then do
  1077.                         /* Get part number - strip any leading zeros */
  1078.                         UUFILE.PARTNUM    = substr(HEADER.ctr_line, LEFT+1, (CENTER-LEFT-1))
  1079.                         UUFILE.PARTNUM    = strip(UUFILE.PARTNUM, leading, '0')
  1080.                         /* Get total parts - strip any leading zeros */
  1081.                         UUFILE.PARTSTOTAL = substr(HEADER.ctr_line, CENTER+1, (RIGHT-CENTER-1))
  1082.                         UUFILE.PARTSTOTAL = strip(UUFILE.PARTSTOTAL, leading, '0')
  1083.                         CONTINUE=NO       /* don't keep searching */
  1084.                      end
  1085.                   end
  1086.                end
  1087.             end
  1088.  
  1089.  
  1090.  
  1091.                 /***************************************************************
  1092.                 GENERIC PART NUMBER SEARCH
  1093.             Check for part pattern: "{1/2}"
  1094.                 ***************************************************************/
  1095.  
  1096.             if (CONTINUE=YES) then do
  1097.                if (DEBUG >= 5) then do
  1098.                   say '*** {} search'
  1099.                end
  1100.                if (verify('{/}', HEADER.ctr_line)=0) then do
  1101.                   LEFT  = pos('{', HEADER.ctr_line)
  1102.                   CENTER= pos('/', HEADER.ctr_line)
  1103.                   RIGHT = pos('}', HEADER.ctr_line)
  1104.                   /* Make sure the pattern components found are part number,
  1105.                      not just erratic characters found in the Subject line */
  1106.                   if (LEFT<CENTER)&(RIGHT>CENTER) then do
  1107.                      UUFILE.PARTNUM    = substr(HEADER.ctr_line, LEFT+1, (CENTER-LEFT-1))
  1108.                      UUFILE.PARTSTOTAL = substr(HEADER.ctr_line, CENTER+1, (RIGHT-CENTER-1))
  1109.                      CONTINUE=NO       /* don't keep searching */
  1110.                   end
  1111.                end
  1112.             end
  1113.  
  1114.  
  1115.  
  1116.                 /***************************************************************
  1117.                 GENERIC PART NUMBER SEARCH
  1118.             Check for part pattern: "part 1/2" (case-insensitive)
  1119.                 ***************************************************************/
  1120.  
  1121.             if (CONTINUE = YES) then do
  1122.                if (DEBUG >= 5) then do
  1123.                   say '*** part 1/2 search'
  1124.                end
  1125.                /* First check for the word "part" */
  1126.                LOC_PART = find(HEADER.ctr_line, 'part')
  1127.                if (LOC_PART > 0) then do
  1128.                   /* When found, get the following word (hopefully x/y information */
  1129.                   WORD_PART = word(HEADER.ctr_line, LOC_PART+1)
  1130.                   /* Check to make sure x/y word contains a slash, denoting part information */
  1131.                   if (verify('/', WORD_PART)=0) then do
  1132.                      /* Slash was found - extract the part information */
  1133.                      CENTER = pos('/', WORD_PART)
  1134.                      UUFILE.PARTNUM    = substr(WORD_PART, 1, CENTER-1)
  1135.                      UUFILE.PARTSTOTAL = substr(WORD_PART, CENTER+1)
  1136.                      CONTINUE=NO       /* don't keep searching */
  1137.                   end
  1138.                end
  1139.             end
  1140.  
  1141.  
  1142.  
  1143.                 /***************************************************************
  1144.                 GENERIC PART NUMBER SEARCH
  1145.             Check for part pattern: "1/2" (case-insensitive, no "part")
  1146.                 ***************************************************************/
  1147.  
  1148.             if (CONTINUE = YES) then do
  1149.                if (DEBUG >= 5) then do
  1150.                   say '*** 1/2 (no part) search'
  1151.                end
  1152.                LOOPAGAIN = YES
  1153.                ctr_word = 1
  1154.                /* Find number of words in Subject line */
  1155.                NUM_WORDS = words(HEADER.ctr_line)
  1156.  
  1157.                do until ((ctr_word > NUM_WORDS)|(LOOPAGAIN=NO))
  1158.                   /* Look for a slash in the word being examined */
  1159.                   WORD_PART = word(HEADER.ctr_line, ctr_word)
  1160.  
  1161.                   if (verify('/', WORD_PART)=0) then do
  1162.                      /* Slash was found - extract the part information */
  1163.                      CENTER = pos('/', WORD_PART)
  1164.                      TMP_PARTNUM    = substr(WORD_PART, 1, CENTER-1)
  1165.                      TMP_PARTSTOTAL = substr(WORD_PART, CENTER+1)
  1166.  
  1167.                      /* only do this if PARTNUM and PARTSTOTAL are numbers */
  1168.                      if ((datatype(TMP_PARTNUM, numeric)=1)&(datatype(TMP_PARTSTOTAL, numeric)=1)) then do
  1169.                         UUFILE.PARTNUM    = TMP_PARTNUM
  1170.                         UUFILE.PARTSTOTAL = TMP_PARTSTOTAL
  1171.                         LOOPAGAIN = NO       /* stop the loop */
  1172.                         CONTINUE  = NO       /* don't keep searching */
  1173.                      end
  1174.                   end
  1175.                   ctr_word = ctr_word + 1
  1176.                end
  1177.             end
  1178.  
  1179.  
  1180.  
  1181.                 /***************************************************************
  1182.                 GENERIC PART NUMBER SEARCH
  1183.             Check for part pattern: "1 of 2"
  1184.                 ***************************************************************/
  1185.  
  1186.                 /* not implemented */
  1187.  
  1188.  
  1189.  
  1190.                 /***************************************************************
  1191.                 GENERIC PART NUMBER SEARCH
  1192.             Check for part pattern: "1of2"
  1193.                 ***************************************************************/
  1194.  
  1195.                 /* not implemented */
  1196.  
  1197.          end
  1198.       end
  1199.    end    
  1200. end
  1201.  
  1202.  
  1203.  
  1204. /***************************************************************************
  1205. SCAN THROUGH HEADER FOR POST-BIN INFORMATION
  1206. Post-Bin uuencoded messages are recognized by the following characteristics:
  1207. - The "pfile=" field bearing the file name (case sensitive)
  1208. - The "part=" field bearing the part name (case sensitive)
  1209. - The phrase "post-bin" must appear in the message (case sensitive)
  1210. ***************************************************************************/
  1211.  
  1212. /* Test condition flags: all must be true before assuming file contains a
  1213.    uuencoded message created using Post-Bin */
  1214.  
  1215. TESTCOND_BEGIN    = FALSE
  1216. TESTCOND_PFILE    = FALSE
  1217. TESTCOND_PART     = FALSE
  1218. TESTCOND_POSTBIN  = FALSE
  1219.  
  1220. /* Scan through the header checking test conditions */
  1221. if (DEBUG >= 5) then do
  1222.    say '*** Post-Bin search'
  1223. end
  1224.  
  1225. do ctr_line = 1 to HEADER.LINES
  1226.    /* Search for file name (PFILE test condition) */
  1227.    if (left(HEADER.ctr_line, 6) = 'pfile=') then do
  1228.       UUFILE.OUTNAME = substr(HEADER.ctr_line, 7, length(HEADER.ctr_line))
  1229.       UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)
  1230.       TESTCOND_PFILE  = TRUE
  1231.    end
  1232.  
  1233.    /* Search for part number (PART test condition) */
  1234.    if (left(HEADER.ctr_line, 5) = 'part=') then do
  1235.       TESTCOND_PART  = TRUE
  1236.       UUFILE.PARTNUM = substr(HEADER.ctr_line, 6, length(HEADER.ctr_line))
  1237.       UUFILE.PARTNUM = space(UUFILE.PARTNUM,0)
  1238.    end
  1239.  
  1240.    /* Search for "post-bin" phrase (POSTBIN test condition) */
  1241.    if (pos('post-bin', HEADER.ctr_line)>0) then do
  1242.       TESTCOND_POSTBIN = TRUE
  1243.    end
  1244.  
  1245.    /* If all test conditions are met, assume message contains a uuencoded
  1246.       message created using Post-Bin */
  1247.    if ((TESTCOND_PFILE = TRUE)&(TESTCOND_PART = TRUE)&(TESTCOND_POSTBIN = TRUE)) then do
  1248.       UUFILE.UUENCODER  = 'Post-Bin'
  1249.       UUFILE.VALID      = YES
  1250.       return SUCCESS
  1251.    end
  1252. end
  1253.  
  1254.  
  1255.  
  1256. /***************************************************************************
  1257. SCAN THROUGH HEADER FOR UBIN-PC INFORMATION
  1258. UBIN-PC uuencoded messages are recognized by the following characteristics:
  1259. - The "BEGIN--cut here--CUT HERE--" sequence just before uuencoded data
  1260. - The phrase "UBIN-PC" might appear in the message (case sensitive, not
  1261.   a requirement for the message to be uuencoded by UBIN-PC)
  1262.  
  1263. The file name of a UBIN-PC encoded message is extracted from the Subject
  1264. line, since there is no field name specifying it, nor do all parts of the
  1265. encoded message contain references to the name other than in the Subject
  1266. line. For this reason, the code used to extract names from Generic uuencoded
  1267. messages is relied upon.
  1268. ***************************************************************************/
  1269.  
  1270. /* Test condition flags: all must be true before assuming file contains a
  1271.    uuencoded message created using UBIN-PC */
  1272.  
  1273. TESTCOND_BEGINCUT = FALSE
  1274. TESTCOND_UBINPC   = FALSE
  1275.  
  1276. /* Scan through the header checking test conditions */
  1277. if (DEBUG >= 5) then do
  1278.    say '*** UBIN-PC search'
  1279. end
  1280.  
  1281. do ctr_line = 1 to HEADER.LINES
  1282.  
  1283.    /* Search for "begin-cut here" sequence (BEGINCUT test condition) */
  1284.    if (pos('BEGIN--cut here--CUT HERE--',HEADER.ctr_line)>0) then do
  1285.       TESTCOND_BEGINCUT = TRUE
  1286.    end
  1287.  
  1288.    /* Search for "UBIN-PC" phrase (UBINPC test condition) */
  1289.    if (pos('UBIN-PC', HEADER.ctr_line)>0) then do
  1290.       TESTCOND_UBINPC = TRUE
  1291.    end
  1292.  
  1293.    /* If all test conditions are met, assume message contains a uuencoded
  1294.       message created using UBIN-PC */
  1295.    if ((TESTCOND_BEGINCUT = TRUE)&&(TESTCOND_UBINPC = TRUE)) then do
  1296.       UUFILE.UUENCODER  = 'UBIN-PC'
  1297.       UUFILE.VALID      = YES
  1298.       return SUCCESS
  1299.    end
  1300. end
  1301.  
  1302.  
  1303.  
  1304. /***************************************************************************
  1305. SCAN THROUGH HEADER FOR UUXFER INFORMATION
  1306. UUXFER uuencoded messages are recognized by the following characteristics:
  1307. - The "BEGIN----------------------Cut Here--------------------------"
  1308.   sequence just before uuencoded data
  1309. - The phrase "UUXFER" might appear in the message (case sensitive, not
  1310.   a requirement for the message to be uuencoded by UUXFER)
  1311.  
  1312. Names are extracted from a line found in the header (contains "UUXFER"
  1313. string). Part numbers are extracted from the Subject line.
  1314. ***************************************************************************/
  1315.  
  1316. /* Test condition flags: all must be true before assuming file contains a
  1317.    uuencoded message created using UUXFER */
  1318.  
  1319. TESTCOND_BEGINCUT = FALSE
  1320. TESTCOND_UUXFER   = FALSE
  1321.  
  1322. /* Scan through the header checking test conditions */
  1323. if (DEBUG >= 5) then do
  1324.    say '*** UUXFER search'
  1325. end
  1326. do ctr_line = 1 to HEADER.LINES
  1327.  
  1328.    /* Search for "begin-cut here" sequence (BEGINCUT test condition) */
  1329.    if (pos('BEGIN----------------------Cut Here--------------------------',HEADER.ctr_line)>0) then do
  1330.       TESTCOND_BEGINCUT = TRUE
  1331.    end
  1332.  
  1333.    /* Search for "UUXFER" phrase (UUXFER test condition) */
  1334.    if (pos('UUXFER', HEADER.ctr_line)>0) then do
  1335.       /* find the name and part on this line */
  1336.       UUFILE.OUTNAME = word(HEADER.ctr_line, 1)
  1337.       UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)
  1338.       TESTCOND_UUXFER = TRUE
  1339.    end
  1340.  
  1341.    /* If all test conditions are met, assume message contains a uuencoded
  1342.       message created using UUXFER */
  1343.    if ((TESTCOND_BEGINCUT = TRUE)&&(TESTCOND_UUXFER = TRUE)) then do
  1344.       UUFILE.UUENCODER  = 'UUXFER'
  1345.       UUFILE.VALID      = YES
  1346.       return SUCCESS
  1347.    end
  1348. end
  1349.  
  1350.  
  1351.  
  1352. /***************************************************************************
  1353. SCAN THROUGH HEADER FOR "UUENCODE (R.E.M.)" INFORMATION
  1354. UUENCODE uuencoded messages are recognized by the following characteristics:
  1355. - The "section (x) of uuencode" sequence just before uuencoded data
  1356.   (case sensitive)
  1357. - The phrase "by R.E.M." (case sensitive)
  1358. ***************************************************************************/
  1359.  
  1360. /* Test condition flags: all must be true before assuming file contains a
  1361.    uuencoded message created using "UUENCODE (R.E.M.)" */
  1362.  
  1363. TESTCOND_SECTIONOF = FALSE
  1364. TESTCOND_BYREM     = FALSE
  1365.  
  1366. /* Scan through the header checking test conditions */
  1367. if (DEBUG >= 5) then do
  1368.    say '*** REM search'
  1369. end
  1370.  
  1371. do ctr_line = 1 to HEADER.LINES
  1372.    /* Search for "section (x) of uuencode" sequence (SECTIONOF test condition) */
  1373.    if (pos('section',HEADER.ctr_line)>0) then do
  1374.       if (pos('of uuencode', HEADER.ctr_line)>0) then do
  1375.          /* File name is stored on same line after "of file"- extract it */
  1376.          REM_NAMELOC = find(HEADER.ctr_line, 'of file')
  1377.          UUFILE.OUTNAME = word(HEADER.ctr_line, REM_NAMELOC+2)
  1378.          UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)
  1379.          TESTCOND_SECTIONOF = TRUE
  1380.       end
  1381.    end
  1382.  
  1383.    /* Search for "section (x) of uuencode" sequence (SECTIONOF test condition) */
  1384.    if (pos('by R.E.M.',HEADER.ctr_line)>0) then do
  1385.          TESTCOND_BYREM = TRUE
  1386.    end
  1387.  
  1388.    /* If all test conditions are met, assume message contains a uuencoded
  1389.       message created using UBIN-PC */
  1390.    if ((TESTCOND_SECTIONOF = TRUE)&(TESTCOND_BYREM = TRUE)) then do
  1391.       UUFILE.UUENCODER  = 'uuencode (R.E.M.)'
  1392.       UUFILE.VALID      = YES
  1393.       return SUCCESS
  1394.    end
  1395. end
  1396.  
  1397.  
  1398.  
  1399. /***************************************************************************
  1400. SCAN THROUGH HEADER FOR GENERIC UUENCODED INFORMATION
  1401. Generic uuencoded messages are recognized by the following characteristics:
  1402. - The "BEGIN --- CUT HERE --- Cut Here --- cut here ---" sequence just
  1403.   before uuencoded data
  1404. ***************************************************************************/
  1405.  
  1406. /* Test condition flags: at least one must be true before assuming file
  1407.    contains a generic uuencoded message */
  1408.  
  1409. TESTCOND_BEGINCUT1   = FALSE
  1410. TESTCOND_BEGINCUT2   = FALSE
  1411. TESTCOND_BEGINCUT3   = FALSE
  1412. TESTCOND_BEGINNUMNAME= FALSE
  1413. TESTCOND_CUTHERE     = FALSE
  1414. TESTCOND_PART1       = FALSE
  1415.  
  1416.  
  1417. /* Scan through the header checking test conditions */
  1418. if (DEBUG >= 5) then do
  1419.    say '*** Generic search'
  1420. end
  1421.  
  1422.  
  1423.  
  1424. do ctr_line = 1 to HEADER.LINES
  1425.  
  1426.    /* Search for "begin <number> <filename>" - primary method (case
  1427.       sensitive. */
  1428.  
  1429.    if (LOOKFORNAME = YES) then do
  1430.       if (pos('begin', HEADER.ctr_line)>0) then do
  1431.          if (DEBUG >= 5) then do
  1432.             say '*** begin line found'
  1433.          end
  1434.          /* Check to ensure second word is a number; if yes, continue */
  1435.          if (datatype(word(HEADER.ctr_line, 2), Numeric)>0) then do
  1436.             if (DEBUG >= 5) then do
  1437.                say '*** 2nd word is number'
  1438.             end
  1439.             /* Extract name from third word */
  1440.             UUFILE.OUTNAME = word(HEADER.ctr_line, 3)        /* get name */
  1441.             UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)    /* strip spaces */
  1442.             TESTCOND_BEGINNUMNAME = TRUE                 /* test condition met */
  1443.             LOOKFORNAME = NO                             /* stop looking for name */
  1444.  
  1445.             /* temp */
  1446.             UUFILE.UUENCODER  = 'Generic'
  1447.             UUFILE.VALID      = YES
  1448.             return SUCCESS
  1449.          end
  1450.       end
  1451.    end
  1452.  
  1453.  
  1454.    /* Search for "begin-cut here" sequence (BEGINCUT1 test condition) */
  1455.    /* Filename does not have to be found for message with this "begin"
  1456.       line to be valid */
  1457.  
  1458.    if (pos('BEGIN --- CUT HERE --- Cut Here --- cut here ---',HEADER.ctr_line)>0) then do
  1459.       if (DEBUG >= 5) then do
  1460.          say '*** found begin/cut'
  1461.       end
  1462.       TESTCOND_BEGINCUT1 = TRUE
  1463.  
  1464.       /* extract name from this line */
  1465.       if (LOOKFORNAME = YES) then do
  1466.          if (DEBUG >= 5) then do
  1467.             say '*** looking for name'
  1468.          end
  1469.  
  1470.          /* word 12 should contain name - if it does, extract it, otherwise
  1471.             keep looking (this is for cases where a message may have the
  1472.             valid "begin-cut here" sequence, but the binary name may be
  1473.             stored elsewhere, such as on a "begin 664 filename" line */
  1474.  
  1475.          if (words(HEADER.ctr_line)>=12) then do
  1476.             if (DEBUG >= 5) then do
  1477.                say '*** found 12th word'
  1478.             end
  1479.             UUFILE.OUTNAME = word(HEADER.ctr_line, 12)   /* 12th word is name */
  1480.             UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)    /* strip spaces from name */
  1481.             LOOKFORNAME    = NO                          /* stop looking for name */
  1482.  
  1483.          end
  1484.       end
  1485.       /* temp */
  1486.       UUFILE.UUENCODER  = 'Generic'
  1487.       UUFILE.VALID      = YES
  1488.       return SUCCESS
  1489.    end
  1490.  
  1491.  
  1492.    /* Search for "BEGIN------------" sequence (BEGINCUT2 test condition) */
  1493.    if (pos('BEGIN------------',HEADER.ctr_line)>0) then do
  1494.       TESTCOND_BEGINCUT2 = TRUE
  1495.       /* extract name from this line */
  1496.       if (LOOKFORNAME = YES) then do
  1497.          UUFILE.OUTNAME = word(HEADER.ctr_line, 2)    /* 2nd word is name */
  1498.          UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)    /* strip spaces from name */
  1499.          LOOKFORNAME    = NO                          /* stop looking for name */
  1500.  
  1501.          /* temp */
  1502.          UUFILE.UUENCODER  = 'Generic'
  1503.          UUFILE.VALID      = YES
  1504.          return SUCCESS
  1505.       end
  1506.    end
  1507.  
  1508.  
  1509.    /* Search for "BEGIN -- CUT HERE -- cut here -- " sequence (BEGINCUT3
  1510.       test condition */
  1511.    if (pos('BEGIN -- CUT HERE -- cut here -- ',HEADER.ctr_line)>0) then do
  1512.       TESTCOND_BEGINCUT3 = TRUE
  1513.       /* extract name from this line */
  1514.       if (LOOKFORNAME = YES) then do
  1515.          UUFILE.OUTNAME = word(HEADER.ctr_line, 9)    /* 9th word is name */
  1516.          UUFILE.OUTNAME = space(UUFILE.OUTNAME, 0)    /* strip spaces from name */
  1517.          LOOKFORNAME    = NO
  1518.  
  1519.          /* temp */
  1520.          UUFILE.UUENCODER  = 'Generic'
  1521.          UUFILE.VALID      = YES
  1522.          return SUCCESS
  1523.       end
  1524.    end
  1525.  
  1526.  
  1527.    /* Search for "------------ Part" sequence (PART1 test condition) */
  1528.    if (pos('------------ Part',HEADER.ctr_line)>0) then do
  1529.       if (DEBUG >= 5) then do
  1530.          say '*** part found (TESTCOND_PART1)'
  1531.       end
  1532.       /* name cannot be extracted from this line - must rely on generic
  1533.          search methods (ie: "Subject" or "begin" lines) */
  1534.       TESTCOND_PART1 = TRUE
  1535.  
  1536.       /* temp */
  1537.       UUFILE.UUENCODER  = 'Generic'
  1538.       UUFILE.VALID      = YES
  1539.       return SUCCESS
  1540.    end
  1541.  
  1542.  
  1543.    /* Search for "CUT HERE" sequence (CUTHERE test condition) */
  1544.    if (pos('------------------------- CUT HERE --------------------------',HEADER.ctr_line)>0) then do
  1545.       if (DEBUG >= 5) then do
  1546.          say '*** CUT HERE found (TESTCOND_CUTHERE)'
  1547.       end
  1548.       /* name cannot be extracted from this line - must rely on generic
  1549.          search methods (ie: "Subject" or "begin" lines) */
  1550.       TESTCOND_CUTHERE = TRUE
  1551.  
  1552.       /* temp */
  1553.       UUFILE.UUENCODER  = 'Generic'
  1554.       UUFILE.VALID      = YES
  1555.       return SUCCESS
  1556.    end
  1557. end
  1558.  
  1559.  
  1560. return SUCCESS
  1561.